t_TOKEN0= r'[0-9]+'
t_TOKEN1= r'\('
t_TOKEN2= r'\)'
t_TOKEN3= r'\*'
t_TOKEN4= r'\+'
t_TOKEN5= r'-'
t_TOKEN6= r'='
t_TOKEN7= r'<='
t_TOKEN8= r'!'
t_TOKEN9= r'&'
t_TOKEN10= r';'
t_TOKEN11= r'[a-zA-Z]\w*'
t_TOKEN12= r':='
t_TOKEN13= r'\{'
t_TOKEN14= r'\}'

reserved = {
	'false':'FALSE',
	'then':'THEN',
	'skip':'SKIP',
	'if':'IF',
	'do':'DO',
	'else':'ELSE',
	'true':'TRUE',
	'while':'WHILE'
}

tokens = ['TOKEN0','TOKEN7','TOKEN12','TOKEN8','TOKEN9','TOKEN2','TOKEN1','TOKEN4','TOKEN3','TOKEN5','TOKEN10','TOKEN6','TOKEN11','TOKEN13','TOKEN14']+list(reserved.values())

t_ignore_0 = r'/\S+/'
t_ignore_1 = r'/\/\/[^\n]*\n/'
t_ignore_2 = r'/\/\*([^*]|\*+[^\/])*\*\//'

precedence = (('right','TOKEN8'),('left','TOKEN3'),('left','TOKEN4','TOKEN5'),('nonassoc','TOKEN6','TOKEN7'),('left','TOKEN9'))

from collections import namedtuple 

class BooleanExpression():
	pass

class ArithmeticExpression():
	pass

class Statement():
	pass

class WhileDo(namedtuple('WhileDo', 'b s'), Statement):
	pass

class IfThenElse(namedtuple('IfThenElse', 'b s1 s2'), Statement):
	pass

class LiteralFalse(BooleanExpression):
	pass

class Addition(namedtuple('Addition', 'a1 a2'), ArithmeticExpression):
	pass

class Assignment(namedtuple('Assignment', 'x a'), Statement):
	pass

class LiteralTrue(BooleanExpression):
	pass

class LessThanOrEqual(namedtuple('LessThanOrEqual', 'a1 a2'), BooleanExpression):
	pass

class Equals(namedtuple('Equals', 'a1 a2'), BooleanExpression):
	pass

class Negation(namedtuple('Negation', 'b'), BooleanExpression):
	pass

class Subtraction(namedtuple('Subtraction', 'a1 a2'), ArithmeticExpression):
	pass

class Skip(Statement):
	pass

class Multiplication(namedtuple('Multiplication', 'a1 a2'), ArithmeticExpression):
	pass

class Numeral(namedtuple('Numeral', 'n'), ArithmeticExpression):
	pass

class Conjuntion(namedtuple('Conjuntion', 'b1 b2'), BooleanExpression):
	pass

start = 'seq'

def p_RULE000(p):	#aexp:/[0-9]+/>(Numeral n=$ 1)
	"aexp : TOKEN0"
	p[0] =(Numeral(n = p[1]))

def p_RULE001(p):	#aexp:'(' aexp ')'>$ 2
	"aexp : TOKEN1 aexp TOKEN2"
	p[0] =p[2]

def p_RULE002(p):	#aexp:aexp '*' aexp>(Multiplication a1=$ 1 a2=$ 3)
	"aexp : aexp TOKEN3 aexp"
	p[0] =(Multiplication(a1 = p[1], a2 = p[3]))

def p_RULE003(p):	#aexp:aexp '+' aexp>(Addition a1=$ 1 a2=$ 3)
	"aexp : aexp TOKEN4 aexp"
	p[0] =(Addition(a1 = p[1], a2 = p[3]))

def p_RULE004(p):	#aexp:aexp '-' aexp>(Subtraction a1=$ 1 a2=$ 3)
	"aexp : aexp TOKEN5 aexp"
	p[0] =(Subtraction(a1 = p[1], a2 = p[3]))

def p_RULE005(p):	#bexp:'true'>(LiteralTrue)
	"bexp : TRUE"
	p[0] =LiteralTrue() 


def p_RULE006(p):	#bexp:'false'>(LiteralFalse)
	"bexp : FALSE"
	p[0] =LiteralFalse() 


def p_RULE007(p):	#bexp:'(' bexp ')'>$ 2
	"bexp : TOKEN1 bexp TOKEN2"
	p[0] =p[2]

def p_RULE008(p):	#bexp:aexp '=' aexp>(Equals a1=$ 1 a2=$ 3)
	"bexp : aexp TOKEN6 aexp"
	p[0] =(Equals(a1 = p[1], a2 = p[3]))

def p_RULE009(p):	#bexp:aexp '<=' aexp>(LessThanOrEqual a1=$ 1 a2=$ 3)
	"bexp : aexp TOKEN7 aexp"
	p[0] =(LessThanOrEqual(a1 = p[1], a2 = p[3]))

def p_RULE0010(p):	#bexp:'!' bexp>(Negation b=$ 2)
	"bexp : TOKEN8 bexp"
	p[0] =(Negation(b = p[2]))

def p_RULE0011(p):	#bexp:bexp '&' bexp>(Conjuntion b1=$ 1 b2=$ 3)
	"bexp : bexp TOKEN9 bexp"
	p[0] =(Conjuntion(b1 = p[1], b2 = p[3]))

def p_RULE0012(p):	#seq:stmt>[$ 1]
	"seq : stmt"
	p[0] =[p[1]]

def p_RULE0013(p):	#seq:seq ';' stmt>$ 1 : $ 3
	"seq : seq TOKEN10 stmt"
	p[0] =__concat__(p[1],p[3])
 
def p_RULE0014(p):	#stmt:/[a-zA-Z]\w*/ ':=' aexp>(Assignment x=$ 1 a=$ 2)
	"stmt : TOKEN11 TOKEN12 aexp"
	p[0] =(Assignment(x = p[1], a = p[2]))

def p_RULE0015(p):	#stmt:'skip'>(Skip)
	"stmt : SKIP"
	p[0] =Skip() 


def p_RULE0016(p):	#stmt:'if' bexp 'then' stmt 'else' stmt>(IfThenElse b=$ 2 s1=$ 4 s2=$ 6)
	"stmt : IF bexp THEN stmt ELSE stmt"
	p[0] =(IfThenElse(b = p[2], s1 = p[4], s2 = p[6]))

def p_RULE0017(p):	#stmt:'while' bexp 'do' stmt>(WhileDo b=$ 2 s=$ 4)
	"stmt : WHILE bexp DO stmt"
	p[0] =(WhileDo(b = p[2], s = p[4]))

def p_RULE0018(p):	#stmt:'{' seq '}'>$ 2
	"stmt : TOKEN13 seq TOKEN14"
	p[0] =p[2]






def __concat__(x,y):
	return (x if type( x ) is list else [x]) + (y if type( y ) is list else [y])

def p_error(t):
	if hasattr(t, 'value'):
		print("Syntax error at '%s'" % t.value)
	else:
		print ("Syntex error")

